#ifndef __CAPAINDICES_INDICES_H
#define __CAPAINDICES_INDICES_H

/*****************************************************************************
*                     Organizaci�n de Datos - 75.06                          *
*                         C�tedra Lic. Servetto                              *
*            Facultad de Ingenier�a - Universidad de Buenos Aires            *
******************************************************************************/

#include "../Comun/Archivo.h"
#include "../Comun/Condiciones.h"

#include <map>

using namespace std;
using namespace Comun;

namespace CapaIndices
{
	
	/*****************************************************************************
	*                                Enumerados                                  *
	******************************************************************************/

	// Enumera los tipos de indices disponibles
	enum TipoIndice
	{

		// Indice Primario, de Identificacion
		// Soporta para las claves solo los tipos:
		// Caracter - Entero Corto - Entero - Fecha - String
		Griego,

		// Indice Secundario, de Clasificacion
		// Soporta todos los tipos:
		// Booleano - Caracter - Entero Corto - Entero - Real - Fecha - String
		Romano

	};

	// Enumera los distintos agrupamientos de los datos a los que apuntan los nodos hijos del arbol.
	// Sirve para saber si el identificador a datos devuelve uno o mas registros dentro del grupo.
	enum TipoDato
	{

		// El identificador se corresponde con un solo registro
		Monovalente,

		// El identificador se corresponde con un grupo de registros
		Polivalente

	};

	/*****************************************************************************
	*                                  Indices                                   *
	******************************************************************************/

	class IIndice;

	// Subcapa de Seleccion de Indices: Obtiene el indice primario de la clase representada por
	// nombreClase. Este metodo es necesario para poder utilizar los indices secundarios.
	IIndice* ObtenerIndicePrimario(string nombreClase);


	// Representa los metadatos necesarios para crear y administrar un indice.
	class MetadatosIndice
	{

	public:

		// Tipo del indice, Griego o Romano
		TipoIndice Tipo;
		// Listado de claves que componen el indice primario. Utilizado en el caso de indices secundarios.
		list< MetadatosAtributo > ClavePrimaria;
		// Listado de claves que componen el indice
		list< MetadatosAtributo > Claves;
		// Listado de atributos presentes en el registro de datos
		list< MetadatosAtributo > CamposRegsitro;

		// Nombre de la clase a la que pertenece el indice.
		// Se utiliza como clave para obtener los datos del archivo maestro.
		string NombreClase;
		// Nombre del archivo de indices, se utiliza como clave para
		// interactuar con la capa fisica.
		string NombreArchivo;
		// Indica el tipo de datos, Monovalente o Polivalente
		CapaIndices::TipoDato TipoDato;
		// Atributos adicionales
		list < ClaveValor > Atributos;

	};

	// Clase que contiene los campos de una clave junto con las restricciones para cada operacion
	// sobre la estructura del indice. Contiene tambien una lista de Registros que cumplen con las condiciones
	// de la operacion.
	class Clave
	{

	public:
		Clave();
		~Clave();

		// Valores de bsqueda para cada campo de la clave. No son las condiciones,
		// sino los parametros para encontrar el primer registro sobre el que se quiere operar.
		list<string> ValoresBusqueda;
		// Condiciones sobre otros campos del registro.
		CondicionCompuesta* OtrasCondiciones;
		// Listado de Registros que cumplen con las condiciones.
		list< Registro >* Resultado;
		// Listado de valores a insertar, en el caso de una insercion o actualizacion.
		list< Atributo > DatosAInsertar;
		// Indica cuantos registros fueron modificados. Se utiliza para informar cuantos registros
		// fueron afectados por la operacion sobre el indice.
		int RegistrosAfectados;
		// Indica si la clave corresponde con mas de un registro, por lo cual la ejecucion
		// se va a efectuar sobre mas de un registro.
		bool EjecucionMultiple;
		
		IIndice* IndicePrimario;

		void FlushResultados(bool ignorarTamanio);

		bool LeerRegistros(list<Registro>* buffer, ifstream* archivo);

		string NombreArchivo;

		list<string>* AtributosASeleccionar;

		bool primerFlush;

		void LeerEncabezado(ifstream* archivo);
		
	private:
		
		list< Registro > inicializadorDeResultado;

		
		
	};


	/// Interfaz que representa las operaciones posibles sobre cualquier indice. Permite crear y administrar un indice.
	class IIndice
	{

	public:
		/// Crea un nuevo indice a partir de la metadata suministrada.
		/// @return true si la creacion fue exitosa, sino false.
		virtual bool Crear() = 0;

		/// Inserta 'clave' en el inidce.
		/// @param clave La clave a insertar.
		virtual void InsertarClave(Clave* clave) = 0;

		/// Busca el registro representado por 'clave' y le asigna sus campos.
		/// @param clave La clave a buscar.
		virtual void BuscarClave(Clave* clave) = 0;

		/// Elimina el registro representado por 'clave'.
		/// @param clave La clave a eliminar.
		virtual void EliminarClave(Clave* clave) = 0;

		/// Actualiza los cambios producidos al registro representado por 'clave'.
		/// @param clave La clave a actualizar.
		virtual void ActualizarClave(Clave* clave) = 0;

		MetadatosIndice* Metadata;

		virtual ~IIndice();

	};

}

#endif
